﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using DeepEarth.Core.Data;
using DeepEarth.Core.Utilities;

namespace DeepEarth.Core.Controls
{
    public class GeoItems : Control
    {
        #region SelectedCommand Property
        public static readonly DependencyProperty SelectedCommandProperty = DependencyProperty.Register( "SelectedCommand", typeof(ICommand), typeof(GeoItems), new PropertyMetadata(SelectedCommandChanged));
        public ICommand SelectedCommand
        {
            get { return GetValue(SelectedCommandProperty) as ICommand; }
            set { SetValue(SelectedCommandProperty, value); }
        }

        static void SelectedCommandChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            var self = (GeoItems)sender;

            if (args.NewValue != null)
            {
                var newValue = args.NewValue as ICommand;
                self.baseViewModel.SelectedCommand = newValue;
            }
        }
        #endregion

        #region NavigateCommand Property
        public static readonly DependencyProperty NavigateCommandProperty = DependencyProperty.Register("NavigateCommand", typeof(ICommand), typeof(GeoItems), new PropertyMetadata(NavigationPropertyChanged));
        public ICommand NavigateCommand
        {
            get { return (ICommand)GetValue(NavigateCommandProperty); }
            set { SetValue(NavigateCommandProperty, value); }
        }

        static void NavigationPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            if (args.NewValue != args.OldValue)
            {
                var self = (GeoItems)sender;
                self.baseViewModel.NavigateCommand = self.NavigateCommand;
            }
        }
        #endregion

        #region ActivationChangedCommand Property
        public static readonly DependencyProperty ActivationChangedCommandProperty = DependencyProperty.Register("ActivationChangedCommand", typeof(ICommand), typeof(GeoItems), new PropertyMetadata(ActivationChangedCommandChanged));
        public ICommand ActivationChangedCommand
        {
            get { return GetValue(ActivationChangedCommandProperty) as ICommand; }
            set { SetValue(SelectedCommandProperty, value); }
        }

        static void ActivationChangedCommandChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            var self = (GeoItems)sender;

            if (args.NewValue != null)
            {
                var newValue = args.NewValue as ICommand;
                self.baseViewModel.ActivationChangedCommand = newValue;
            }
        }

        public static readonly DependencyProperty ShowDetailsChangedCommandProperty = DependencyProperty.Register("ShowDetailsChangedCommand", typeof(ICommand), typeof(GeoItems), new PropertyMetadata(ShowDetailsChangedCommandChanged));
        public ICommand ShowDetailsChangedCommand
        {
            get { return (ICommand)GetValue(ShowDetailsChangedCommandProperty); }
            set { SetValue(ShowDetailsChangedCommandProperty, value); }
        }

        static void ShowDetailsChangedCommandChanged (DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            var self = (GeoItems)sender;

            if (args.NewValue != null)
            {
                var newValue = args.NewValue as ICommand;
                self.baseViewModel.ShowDetailsChangedCommand = newValue;
            }
        }
        
        #endregion

        public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(GeoItems), new PropertyMetadata(ItemsSourceChanged));
        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        static void ItemsSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            var self = (GeoItems)sender;
            self.baseViewModel.ChildItemsSource = args.NewValue == null ? null : args.NewValue as IEnumerable;
        }
        
        public GeoItems()
        {
            baseViewModel = new GeoItemViewModel {Data = this};
        }

        GeoItemViewModel baseViewModel;

        public ObservableCollection<GeoItemViewModel> ViewModels
        {
            get { return baseViewModel.Children; }
        }

        public bool Contains(object o)
        {
            return baseViewModel.Contains(o);
        }

        public void Add(object o)
        {
            baseViewModel.Add(o);
        }

        public void Remove(object o)
        {
            baseViewModel.Remove(o);
        }

        public void Clear()
        {
            baseViewModel.Clear();
        }

        #region Utilities
        public IEnumerable<object> GetVisibleObjects()
        {
            var selections = SelectWithSelector(v => v.IsActive, baseViewModel.Children);
            return selections.Select(vm => vm.Data);
        }

        public IEnumerable<T> GetVisibleObjects<T>()
        {
            var selections = SelectWithSelector(v => v.IsActive && v.Data is T, baseViewModel.Children);
            return selections.Select<GeoItemViewModel, T>(o => (T)o.Data);
        }

        static IEnumerable<GeoItemViewModel> SelectWithSelector(Func<GeoItemViewModel, bool> selector, IEnumerable<GeoItemViewModel> viewModels)
        {
            var vms = viewModels.Where(selector).Concat(viewModels.SelectMany(v => SelectWithSelector(selector, v.Children)));

            return vms;
        }
        #endregion
    }
}